<?php

class SaeImage extends SaeObject {

	private $_img_data = ''; //图片数据
	private $_options = array(); //图片选项
	private $_width = 0;
	private $_height = 0;
	private $_image = null; //存储image资源

	const image_limitsize = 2097152;

	public function __construct($img_data='') {
		parent::__construct();
		return $this->setData($img_data);
	}

	//添加文字注释
	public function annotate($txt, $opacity=0.5, $gravity=SAE_Static, $font=array()) {
		$opacity = floatval($opacity);
		if ($this->imageNull())
		return false;
		//设置默认字体样式
		$font_default = array('name' => SAE_SimSun, 'size' => 15, 'weight' => 300, 'color' => 'black');
		$font = array_merge($font_default, $font);
		array_push($this->_options, array('act' => 'annotate', "txt" => $txt, "opacity" => $opacity,
            "gravity" => $gravity, "font" => array("name" => $font['name'], "size" => $font["size"],
                "weight" => $font["weight"], "color" => $font["color"])));
		return true;
	}

	//数据重新初始化
	public function clean() {
		$this->_img_data = '';
		$this->_options = array();
		$this->_width = 0;
		$this->_height = 0;
		$this->_image = null;
	}

	//图片合成, data为数组，在其他操作执行前进行操作
	public function composite($width, $height, $color="black") {
		$width = intval($width);
		$height = intval($height);
		if ($this->imageNull())
		return false;
		array_push($this->_options, array('act' => 'composite', "width" => $width, "height" => $height, "color" => $color));
		return true;
	}

	//裁剪图片
	public function crop($lx=0.25, $rx=0.75, $by=0.25, $ty=0.75) {
		$lx = floatval($lx);
		$rx = floatval($rx);
		$by = floatval($by);
		$ty = floatval($ty);
		if ($this->imageNull())
		return false;
		array_push($this->_options, array('act' => 'crop', "lx" => $lx, "rx" => $rx, "by" => $by, "ty" => $ty));
		return true;
	}

	//进行图片处理操作
	public function exec($format='jpg', $display=false) {
		if ($this->imageNull())
		return false;
		if (!in_array($format, array('jpg', 'gif', 'png'))) {
			$this->errno = SAE_ErrParameter;
			$this->errmsg = "format must be one of 'jpg', 'gif' and 'png'";
			return false;
		}
		if ($format == "jpg")
		$format = "jpeg";
		if ($this->_options[0]["act"] == "composite" && !is_array($this->_img_data)) {
			$this->errno = SAE_ErrParameter;
			$this->errmsg = "composite imagedata must be an array, pls see doc:";
			return false;
		}
		if ($this->_options[0]["act"] != "composite" && is_array($this->_img_data)) {
			$this->errno = SAE_ErrParameter;
			$this->errmsg = "imagedata is array only when composite image and composite must be the first operation";
			return false;
		}
		if (!$this->_image_create())
		return false;
		//循环处理
		foreach ($this->_options as $options) {
			call_user_func(array($this, "_" . $options['act']), $options);
		}
		$imgFun = 'image' . $format;
		if ($display) {
			header("Content-Type: image/" . $format);
			$imgFun($this->_image);
		} else {
			ob_start();
			$imgFun($this->_image);
			return ob_get_clean();
		}
		imagedestroy($this->_image);
	}

	//创建画布
	private function _image_create() {
		if ($this->_options[0]["act"] == "composite") {
			//合并多张图片
			$w = $this->_options[0]["width"];
			$h = $this->_options[0]["height"];
			$this->_width=$w;
			$this->_height=$h;
			$_image = imagecreatetruecolor($w, $h);
			//设置背景颜色
			$color = $this->toRGB($this->_options[0]['color']);
			$bg = imagecolorallocate($_image, $color['r'], $color['g'], $color['b']);
			imagefill($_image, 0, 0, $bg);
			foreach ($this->_img_data as $data) {
				$img_data = $data[0];
				$x = isset($data[1]) ? $data[1] : 0;
				$y = isset($data[2]) ? $data[2] : 0;
				$o = isset($data[3]) ? $data[3] * 100 : 100;
				$p = isset($data[4]) ? $data[4] : SAE_TOP_LEFT;
				$tmp_file = tempnam(SAE_TMP_PATH, "SAE_IMAGE");
				if (!file_put_contents($tmp_file, $img_data)) {
					$this->errmsg = "file_put_contents to SAETMP_PATH failed when getImageAttr";
					return false;
				}
				$info = getimagesize($tmp_file);
				$sw = $info[0];
				$sh = $info[1];
				$image_type = strtolower(substr(image_type_to_extension($info[2]), 1));
				$createFun = "imagecreatefrom" . $image_type;
				$sImage = $createFun($tmp_file);
				//设置位置
				switch ($p) {
					case SAE_TOP_LEFT:
						$dst_x = $x;
						$dst_y = -$y;
						break;
					case SAE_TOP_CENTER:
						$dst_x = ($w - $sw) / 2 + $x;
						$dst_y = -$y;
						break;
					case SAE_TOP_RIGHT:
						$dst_x = $w - $sw + $x;
						$dst_y = -$y;
						break;
					case SAE_CENTER_LEFT:
						$dst_x = $x;
						$dst_y = ($h - $sh) / 2 - $y;
						break;
					case SAE_CENTER_CENTER:
						$dst_x = ($w - $sw) / 2 + $x;
						$dst_y = ($h - $sh) / 2 - $y;
						break;
					case SAE_CENTER_RIGHT:
						$dst_x = $w - $sw + $x;
						$dst_y = ($h - $sh) / 2 - $y;
						break;
					case SAE_BOTTOM_LEFT:
						$dst_x = $x;
						$dst_y = $h - $sh - $y;
						break;
					case SAE_BOTTOM_CENTER:
						$dst_x = ($w - $sw) / 2 + $x;
						$dst_y = $h - $sh - $y;
						break;
					case SAE_BOTTOM_RIGHT:
						$dst_x = $w - $sw + $x;
						$dst_y = $h - $sh - $y;
						break;
				}
				$this->imagecopymerge_alpha($_image, $sImage, $dst_x, $dst_y, 0, 0, $sw, $sh, $o);
				unlink($tmp_file);
			}

			$this->_image = $_image;
			unset($this->_options[0]);
		} else {
			if (is_null($this->_image))
			$this->getImageAttr();
		}
		return true;
	}
	//修复合并时png透明问题
	private function imagecopymerge_alpha($dst_im, $src_im, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h, $pct){
		$w = imagesx($src_im);
		$h = imagesy($src_im);
		$cut = imagecreatetruecolor($src_w, $src_h);
		imagecopy($cut, $dst_im, 0, 0, $dst_x, $dst_y, $src_w, $src_h);
		imagecopy($cut, $src_im, 0, 0, $src_x, $src_y, $src_w, $src_h);
		imagecopymerge($dst_im, $cut, $dst_x, $dst_y, $src_x, $src_y, $src_w, $src_h,$pct);
	}

	//水平翻转
	public function flipH() {
		if ($this->imageNull())
		return false;
		array_push($this->_options, array('act' => 'flipH'));
		return true;
	}

	//垂直翻转
	public function flipV() {
		if ($this->imageNull())
		return false;
		array_push($this->_options, array('act' => 'flipV'));
		return true;
	}

	//获取图像属性
	public function getImageAttr() {
		if ($this->imageNull())
		return false;
		$fn = tempnam(SAE_TMP_PATH, "SAE_IMAGE");
		if ($fn == false) {
			$this->errmsg = "tempnam call failed when getImageAttr";
			return false;
		}
		if (!file_put_contents($fn, $this->_img_data)) {
			$this->errmsg = "file_put_contents to SAETMP_PATH failed when getImageAttr";
			return false;
		}
		if (!($size = getimagesize($fn, $info))) {
			$this->errmsg = "getimagesize failed when getImageAttr";
			return false;
		}
		foreach ($info as $k => $v) {
			$size[$k] = $v;
		}
		$this->_width = $size[0];
		$this->_height = $size[1];
		//建立图片资源
		$image_type = strtolower(substr(image_type_to_extension($size[2]), 1));
		$createFun = "imagecreatefrom" . $image_type;
		$this->_image = $createFun($fn);
		unlink($fn); //删除临时文件
		return $size;
	}

	//去噪点，改善图片质量，通常用于exec之前
	public function improve() {
		if ($this->imageNull())
		return false;
		array_push($this->_options, array('act' => 'improve'));
		return true;
	}

	//等比例缩放
	public function resize($width=0, $height=0) {
		$width = intval($width);
		$height = intval($height);
		if ($this->imageNull())
		return false;
		array_push($this->_options, array('act' => 'resize', "width" => $width, "height" => $height));
		return true;
	}

	//按比例缩放
	public function resizeRatio($ratio=0.5) {
		$ratio = floatval($ratio);
		if ($this->imageNull())
		return false;
		if ($this->_width == 0) {
			$attr = $this->getImageAttr();
			if (!$attr)
			return false;
		}
		array_push($this->_options, array('act' => 'resize', "width" => $this->_width * $ratio, "height" => $this->_height * $ratio));
		return true;
	}

	//顺时针旋转图片
	public function rotate($degree=90) {
		$degree = intval($degree);
		if ($this->imageNull())
		return false;
		array_push($this->_options, array('act' => 'rotate', "degree" => $degree));
		return true;
	}

	//设置数据
	public function setData($img_data) {
		if (is_array($img_data)) {
			$_size = 0;
			foreach ($img_data as $k => $i) {
				if (count($i) < 1 || count($i) > 5) {
					$this->errno = SAE_ErrParameter;
					$this->errmsg = "image data array you supplied invalid";
					return false;
				}
				if (is_null($i[1]) || $i[1] === false)
				$img_data[$k][1] = 0;
				if (is_null($i[2]) || $i[1] === false)
				$img_data[$k][2] = 0;
				if (is_null($i[3]) || $i[1] === false)
				$img_data[$k][3] = 1;
				if (is_null($i[4]) || $i[1] === false)
				$img_data[$k][4] = SAE_TOP_LEFT;
				$_size += strlen($i[0]);
			}
			if ($_size > self::image_limitsize) {
				$this->errno = SAE_ErrParameter;
				$this->errmsg = "image datas length more than 2M";
				return false;
			}
		} else if (strlen($img_data) > self::image_limitsize) {
			$this->errno = SAE_ErrParameter;
			$this->errmsg = "image data length more than 2M";
			return false;
		}
		$this->_img_data = $img_data;

		return true;
	}

	//判断图片数据是否可用
	private function imageNull() {
		if (empty($this->_img_data)) {
			$this->errno = SAE_ErrParameter;
			$this->errmsg = "image data cannot be empty";
			return true;
		} else {
			return false;
		}
	}

	//将颜色转换为RGB格式
	private function toRGB($color) {
		$color = trim($color);
		if (preg_match('/^rgb\((\d+),(\d+),(\d+)\)$/i', $color, $arr)) {
			//支持rgb(r,g,b)格式
			return array(
                'r' => $arr[1],
                'g' => $arr[2],
                'b' => $arr[3]
			);
		}
		$e_color = array(
		//支持英文颜色名
            'black' => '#000',
            'red' => '#f00',
            'blue'=>'#00f'
            //TODU 增加其他
		);
		$hexColor = str_replace(array_keys($e_color), array_values($e_color), $color);
		$color = str_replace('#', '', $hexColor);
		if (strlen($color) > 3) {
			$rgb = array(
                'r' => hexdec(substr($color, 0, 2)),
                'g' => hexdec(substr($color, 2, 2)),
                'b' => hexdec(substr($color, 4, 2))
			);
		} else {
			$color = str_replace('#', '', $hexColor);
			$r = substr($color, 0, 1) . substr($color, 0, 1);
			$g = substr($color, 1, 1) . substr($color, 1, 1);
			$b = substr($color, 2, 1) . substr($color, 2, 1);
			$rgb = array(
                'r' => hexdec($r),
                'g' => hexdec($g),
                'b' => hexdec($b)
			);
		}
		return $rgb;
	}

	/**
	 * 添加文字
	 * 参数格式
	 *   array("txt" => $txt, "opacity" => $opacity,
	 "gravity" => $gravity, "font" => array("name" => $font['name'], "size" => $font["size"],
	 "weight" => $font["weight"], "color" => $font["color"]))
	 * @param array $args
	 */
	private function _annotate($args) {
		$font = $args['font'];
		$rgb = $this->toRGB($font['color']);
		$color = imagecolorclosestalpha($this->_image, $rgb['r'], $rgb['g'], $rgb['b'], (1 - $args['opacity']) * 100);
		//设置位置
		$fontSize = imagettfbbox($font['size'], 0, $font['name'], $args['txt']);
		$textWidth = $fontSize [4]; //取出宽
		$textHeight = abs($fontSize[7]); //取出高
		switch ($args['gravity']) {
			case SAE_NorthWest:
				$x=0;
				$y=$textHeight;
				break;
			case SAE_North:
				$x=($this->_width-$textWidth)/2;;
				$y=$textHeight;
				break;
			case SAE_NorthEast:
				$x=$this->_width-$textWidth;;
				$y=$textHeight;
				break;
			case SAE_West:
				$x=0;
				$y=($this->_height-$textHeight)/2;
				break;
			case SAE_East:
				$x=$this->_width-$textWidth;
				$y=($this->_height-$textHeight)/2;
				break;
			case SAE_SouthWest:
				$x=0;
				$y=$this->_height-$textHeight;
				break;
			case SAE_South:
				$x=($this->_width-$textWidth)/2;
				$y=$this->_height-$textHeight;
				break;
			case SAE_SouthEast:
				$x=$this->_width-$textWidth;
				$y=$this->_height-$textHeight;
				break;
			case SAE_Static:
			default :
				$x=($this->_width-$textWidth)/2;
				$y=($this->_height-$textHeight)/2;
				break;
		}
		imagettftext($this->_image, $font['size'], 0, $x, $y, $color, $font['name'], $args['txt']);
	}
	/**
	 *截取图片
	 * 参数 array("lx" => $lx, "rx" => $rx, "by" => $by, "ty" => $ty)
	 * @param array $args
	 */
	private function _crop($args){
		$width=($args['rx']-$args['lx'])*$this->_width;
		$height=($args['ty']-$args['by'])*$this->_height;
		$x=$args['lx']*$this->_width;
		$y=$args['by']*$this->_height;
		$_image=imagecreatetruecolor($width, $height);
		imagecopyresampled($_image,$this->_image,0,0,$x,$y,
		$width,$height,$width,$height);
		$this->_image=$_image;
	}
	/**
	 *图片放缩
	 * 参数：array( "width" => $width, "height" => $height)
	 * @param array $args
	 */
	private function _resize($args){
		if($args['width']==0 && $args['heigth']==0) return ;
		if($args['width']==0){
			//高度固定等比例放缩
			$h=$args['heigth'];
			$w=$h/$this->_height*$this->_width;
		}elseif($args['heigth']==0){
			//宽度固定等比例放缩
			$w=$args['width'];
			$h=$w/$this->_width*$this->_height;
		}else{
			$w=$args['width'];
			$h=$args['height'];
		}
		$_image=imagecreatetruecolor($w, $h);
		imagecopyresampled($_image, $this->_image, 0, 0, 0, 0, $w, $h, $this->_width, $this->_height);
		$this->_image=$_image;
	}
	/**
	 *旋转角度
	 * @param array $args
	 */
	private function _rotate($args){
		$this->_image=imagerotate($this->_image, 360-$args['degree'],0);
	}
	//水平翻转
	private function _flipH($args) {
		$_image=imagecreatetruecolor($this->_width, $this->_height);
		for ($i = 0; $i < $this->_width; $i++) {
			imagecopyresampled($_image, $this->_image, ($this->_width - $i), 0, $i, 0, 1, $this->_height, 1, $this->_height);
		}
		$this->_image=$_image;
	}
	//垂直翻转
	private function _flipV($args) {
		$this->_flipH(array());
		$this->_rotate(array('degree'=>180));
	}
	//去除噪点
	private function _improve($args){
		//本地不做任何处理
	}

}